/*!
 * jquery.contextMenu.js
 * Date: 2013-10-17 20:31:03
 */
;(function ($){
    function returnfalse(){
        return false;
    };

    $.fn.contextmenu = function (option){
        option = $.extend({
                alias : 'cmroot',
                width : 150
            }, option);
        var ruleName = null, target = null, groups = {}, mitems = {}, actions = {}, showGroups = [];
        var itemTpl = "<div class='b-m-$[type]' unselectable=on><nobr unselectable=on><img src='static/plugins/contextMenu/icons/$[icon].gif' align='absmiddle'/><span unselectable=on>$[text]</span></nobr></div>";
        var gTemplet = $('<div/>').addClass('b-m-mpanel').attr('unselectable', 'on').css('display', 'none');
        var iTemplet = $('<div/>').addClass('b-m-item').attr('unselectable', 'on');
        var sTemplet = $('<div/>').addClass('b-m-split');

        //build group item, which has sub items
        var buildGroup = function (obj, mid){
            groups[obj.alias] = this;
            this.gidx = obj.alias;
            this.id = obj.alias;
            if (obj.disable){
                this.disable = obj.disable;
                this.className = 'b-m-idisable';
            }
            $(this).width(obj.width).click(returnfalse).mousedown(returnfalse).appendTo($(mid));
            obj = null;
            return this;
        };
        var buildItem = function (obj){
            var T = this;
            T.title = obj.text;
            T.idx = obj.alias;
            T.gidx = obj.gidx;
            T.data = obj;
            T.innerHTML = itemTpl.replace(/\$\[([^\]]+)\]/g, function (){
                    return obj[arguments[1]];
                });
            if (obj.disable){
                T.disable = obj.disable;
                T.className = 'b-m-idisable';
            }
            obj.items && (T.group = true);
            obj.action && (actions[obj.alias] = obj.action);
            mitems[obj.alias] = T;
            T = obj = null;
            return this;
        };

        //add new items
        var addItems = function (gidx, items){
            var tmp = null;
            for (var i = 0; i < items.length; i++){
                if (items[i].type == 'splitLine'){
                    //split line
                    tmp = sTemplet.clone()[0];
                } else {
                    items[i].gidx = gidx;
                    if (items[i].type == 'group'){
                        //group
                        buildGroup.apply(gTemplet.clone()[0], [items[i]]);
                        arguments.callee(items[i].alias, items[i].items);
                        items[i].type = 'arrow';
                        tmp = buildItem.apply(iTemplet.clone()[0], [items[i]]);
                    } else {
                        //normal item
                        items[i].type = 'ibody';
                        tmp = buildItem.apply(iTemplet.clone()[0], [items[i]]);
                        $(tmp).click(function (e){
                            if (!this.disable){
                                if ($.isFunction(actions[this.idx])){
                                    actions[this.idx].call(this, $(target));
                                }
                                hideMenuPane();
                            }
                            return false;
                        });

                    } //end if
                    $(tmp).bind('contextmenu', returnfalse).hover(overItem, outItem);
                }
                groups[gidx].appendChild(tmp);
                tmp = items[i] = items[i].items = null;
            } //end for
            gidx = items = null;
        };
        var overItem = function (e){
            //menu item is disabled
            if (this.disable)
                return false;
            hideMenuPane.call(groups[this.gidx]);
            //has sub items
            if (this.group){
                var pos = $(this).offset();
                var width = $(this).outerWidth();
                showMenuGroup.apply(groups[this.idx], [pos, width]);
            }
            this.className = 'b-m-ifocus';
            return false;
        };
        //menu loses focus
        var outItem = function (e){
            //disabled item
            if (this.disable)
                return false;
            if (!this.group){
                //normal item
                this.className = 'b-m-item';
            } //Endif
            return false;
        };
        //show menu group at specified position
        var showMenuGroup = function (pos, width){
            var bwidth = $('body').width();
            var bheight = document.documentElement.clientHeight;
            var mwidth = $(this).outerWidth();
            var mheight = $(this).outerHeight();
            pos.left = (pos.left + width + mwidth > bwidth) ? (pos.left - mwidth < 0 ? 0 : pos.left - mwidth) : pos.left + width;
            pos.top = (pos.top + mheight > bheight) ? (pos.top - mheight + (width > 0 ? 25 : 0) < 0 ? 0 : pos.top - mheight + (width > 0 ? 25 : 0)) : pos.top;
            $(this).css(pos).show();
            showGroups.push(this.gidx);
        };
        //to hide menu
        var hideMenuPane = function (){
            var alias = null;
            for (var i = showGroups.length - 1; i >= 0; i--){
                if (showGroups[i] == this.gidx)
                    break;
                alias = showGroups.pop();
                groups[alias].style.display = 'none';
                mitems[alias] && (mitems[alias].className = 'b-m-item');
            } //Endfor
            //CollectGarbage();
        };
        function applyRule(rule){
            if (ruleName && ruleName == rule.name)
                return false;
            for (var i in mitems)
                disable(i, !rule.disable);
            for (var i = 0; i < rule.items.length; i++)
                disable(rule.items[i], rule.disable);
            ruleName = rule.name;
        };
        function disable(alias, disabled){
            var item = mitems[alias];
            item.className = (item.disable = item.lastChild.disabled = disabled) ? 'b-m-idisable' : 'b-m-item';
        };

        /* to show menu  */
        function showMenu(e, menutarget){
            target = menutarget;
            showMenuGroup.call(groups.cmroot, {
                left : e.pageX,
                top : e.pageY
            }, 0);
            $(document).one('mousedown', hideMenuPane);
        }
        var $root = $('#' + option.alias);
        var root = null;

        // if ($root.length == 0){
        if (1){
            root = buildGroup.apply(gTemplet.clone()[0], [option, option.mid]);
            root.applyrule = applyRule;
            root.showMenu = showMenu;
            addItems(option.alias, option.items);
        } else {
            root = $root[0];
        }

        var me = $(this).each(function (){
                return $(this).bind('contextmenu', function (e){
                    var bShowContext = (option.onContextMenu && $.isFunction(option.onContextMenu)) ? option.onContextMenu.call(this, e) : true;
                    if (bShowContext){
                        if (option.onShow && $.isFunction(option.onShow)){
                            option.onShow.call(this, root);
                        }
                        root.showMenu(e, this);
                    }
                    return false;
                });
            });

        //to apply rule
        if (option.rule){
            applyRule(option.rule);
        }
        gTemplet = iTemplet = sTemplet = itemTpl = buildGroup = buildItem = null;
        addItems = overItem = outItem = null;
        //CollectGarbage();
        return me;
    }
})(jQuery);
